﻿using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Text;
using CommServer.Cache;
using CommServer.Common;
using CommServer.Common.Json;
using CommServer.Network;
using CommServer.Protocol;
using CommServer.Tasks;
using CommServer.Tasks.Common;
using System.Linq;

namespace CommServer
{
    public class DeviceServer
    {
        //原始事件
        public event Action<string> OnConnect;
        public event Action<string, string> OnDisConnect;
        public event Action<string, string> OnLogin;

        public event Action<dynamic> OnInvDataReceive;
        public event Action<dynamic> OnMeterDataReceive;
        public event Action<List<dynamic>> OnAlarmDataReceive;
        public event Action<dynamic> OnSensorDataReceive;
        public event Action<byte[]> OnMaintainFrameReceive;
        private Dictionary<string, Dictionary<int, string>> m_AlarmDesMap = new Dictionary<string, Dictionary<int, string>>();

        private TcpServer m_TcpServer;
        private Task_SessionCheck task_SessionCheck = new Task_SessionCheck(DateTime.Now, 60, IntervalUnit.Second);
        public DeviceServer()
        {
            m_TcpServer = new TcpServer();
            m_TcpServer.OnConnect += new Action<TcpSession>((Session) =>
            {
                OnConnect?.Invoke(Session.SessionId);
            });
            m_TcpServer.OnDisConnect += new Action<TcpSession>((Session) =>
            {
                OnDisConnect?.Invoke(Session.SessionId, Session.TagString);
            });

            m_TcpServer.OnReceive += new Action<TcpSession>((Session) =>
            {
                OnReceiveDo(Session);
            });

            m_AlarmDesMap.Add("1", m_AlarmDesMapV1);
            m_AlarmDesMap.Add("2", m_AlarmDesMapV2);
            initATSAlarm();
            initHWAlarm();
        }
        private Dictionary<int, string> m_AlarmDesMapV2 = new Dictionary<int, string>()
        {
            { 101,"逆变器故障" },
            {102," 直流过压" },
            {103," 电网过压" },
            {104," 电网欠压" },
            {105," 变压器过温" },
            {106 ,"频率异常" },
            {107 ,"孤岛装置" },
            {108 ,"硬件故障" },
            {109 ,"接地故障" },
            {110 ,"模块故障" },
            {111 ,"接触器故障" },
            {112 ,"电网过频" },
            {113 ,"电网欠频" },
            {114 ,"直流母线过压" },
            {115 ,"直流母线欠压" },
            {116 ,"逆变过压" },
            {117 ,"输出过载" },
            {118 ,"降额运行" },
            {119 ,"M-S通信错误" },
            {120 ,"EEPROM读写错误" },
            {121 ,"RELAY检查错误" },
            {122 ,"DC Injection High" },
            {123 ,"AC HTC Failure code 01" },
            {124 ,"GFCI Device Failure" },
            {125 ,"M-S version unmatched" },
            {126 ,"FacFailure:Fac out of range" },
            {127 ,"AC Voltage out of range" },
            {128 ,"Utility Loss" },
            {129 ,"GFCI Failure" },
            {130 ,"PV Over Voltage" },
            {131 ,"Isolation Fault" },
            {132 ,"Fan Lock" },
            {133 ,"Over Temperature In Inverter" },
            {134 ,"Cons Fault:VacDif for M-S" },
            {135 ,"Cons Fault:FacDif for M-S" },
            {136 ,"Cons Fault:Groud I Dif for M-S" },
            {137 ,"Cons Fault:DC inj. for M-S" },
            {138 ,"Cons Fault:Fac,VacDif for M-S" },
            {139 ,"High Dc Bus" },
            {140 ,"Consistent Fault" },
            {141 ,"Average volt of 10 min fault" },
            {142 ,"PV1-SPD Fault" },
            {143 ,"PV2-SPD Fault" },
            {144 ,"Fuse Fault" },
            {145 ,"JL_No grid" },
            {146 ,"JL_Unbalanced power grid" },
            {147 ,"JL_Over Current" },
            {148 ,"DC bus voltage anomaly" },
            {149 ,"DC bus voltage anomaly1" },
            {150 ,"DC Over Current a" },
            {151 ,"DC Over Current b" },
            {152 ,"DC Hardware over current" },
            {153 ,"JL_Short-circuit protec" },
            {154 ,"JL_Init protection" },
            {155 ,"Leakage current protec" },
            {156 ,"12V Undervoltageprotec" },
            {157 ,"Arc s_checkprotec" },
            {158 ,"Arc Error" },
            {159," 自测失败" },
            {160 ,"绝缘故障" },
            {161 ,"漏电流故障" },
            {162 ,"一致性故障" },
            {163 ,"直流分量故障" },
            {164 ,"存储失败" },
            {165 ,"升压故障" },
            {166 ,"漏电保护装置故障" },
            {167 ,"逆变过流" },
            {168 ,"风扇故障" },
            {169 ,"时钟故障" },
            {170 ,"外部通讯故障" },
            {171 ,"参考电压故障" },
            {172 ,"母线不平衡" },
            {173 ,"机型不匹配" },
            {174 ,"输入过流" },
            {175 ,"输出电流不平衡" },
            {176,"电网电站故障" }

        };
        private Dictionary<int, string> m_AlarmDesMapV1 = new Dictionary<int, string>()
        {
            { 101,"逆变器故障" },
            { 102,"直流过压" },
            { 103,"电网过压" },
            { 104,"电网欠压" },
            { 105,"变压器过温" },
            { 106,"频率异常" },
            { 107,"孤岛故障" },
            { 108,"硬件故障" },
            { 109,"接地故障" },
            { 110,"模块故障" },
            { 111,"接触器故障" },
            { 112,"电网过频" },
            { 113,"电网欠频" },
            { 114,"直流母线过压" },
            { 115,"直流母线欠压" },
            { 116,"逆变过压" },
            { 117,"输出过载" },
            { 118,"降额运行" },
            {119,"Comm Fails Between M-S"},
            {120,"EEPROM R/W Fail"},
            {121,"Relay Check Fail"},
            {122,"DC Injection High"},
            {123,"AC HTC Failure code 01"},
            {124,"GFCI Device Failure"},
            {125,"M-S version unmatched"},
            {126,"Fac Failure:Fac out of range"},
            {127,"AC Voltage out of range"},
            {128,"Utility Loss"},
            {129,"GFCI Failure"},
            {130,"PV Over Voltage"},
            {131,"Isolation Fault"},
            {132,"Fan Lock"},
            {133,"Over Temperature In Inverter"},
            {134,"Cons Fault:Vac Dif for M-S"},
            {135,"Cons Fault:Fac Dif for M-S"},
            {136,"Cons Fault:Groud I Dif for M-S"},
            {137,"Cons Fault:DC inj. for M-S"},
            {138,"Cons Fault:Fac,Vac Dif for M-S"},
            {139,"High Dc Bus"},
            {140,"Consistent Fault"},
            {141,"Average volt of 10 min fault"},
            {142,"PV1-SPD Fault"},
            {143,"PV2-SPD Fault"},
            {144,"Fuse Fault"},
            {145,"无电网"},
            {146,"电网不平衡"},
            {147,"过流"},
            {148,"直流母线不均压"},
            {149,"直流母线不均压2"},
            {150,"直流过流A"},
            {151,"直流过流B"},
            {152,"直流过流硬件过流"},
            {153,"短路保护"},
            {154,"初始化保护"},
            {155,"漏电流保护"},
            {156,"12V欠压保护"},
            {157,"电弧自检保护"},
            {158,"电弧故障" }
        };

        private Dictionary<int, string> m_AlarmDesMapATS64 = new Dictionary<int, string>() {
            {001,   "母线瞬时过压" },
            {002,   "PV1过流" },
            {003,   " PV2过流" },
            {004,   " PV3过流" },
            {005 ,   "PV4过流" },
            {006 ,   "直流输入PV1反接故障" },
            {007 ,   "直流输入PV2反接故障" },
            {008 ,   "母线过压硬件故障" },
            {009 ,   "PV硬件过流故障" },
            {010 ,   "PV电压超过BUS电压"} };
        private Dictionary<int, string> m_AlarmDesMapATS60 = new Dictionary<int, string>() {
            {401 ,   "FRAM读取告警"},
            {402 ,   "环境温度传感器开路告警"},
            {403 ,   "环境温度传感器短路告警"},
            {404 ,   "逆变温度传感器开路告警"},
            {405 ,   "逆变温度传感器短路告警"},
            {406 ,   "PV高压过功率告警"},
            {407 ,   "环境温度低温传感器开路告警"},
            {408 ,   "风扇转速偏低告警"},
            {409 ,   "风扇堵转告警"},
            {410 ,   "电表通讯异常告警"},
            {411 ,   "BOOST短路告警"}};
        private Dictionary<int, string> m_AlarmDesMapATS61 = new Dictionary<int, string>() {
            {101 ,   "电网过压"},
            {102 ,   "电网暂态过压"},
            {103 ,   "电网欠压"},
            {104 ,   "电网低压"},
            {105 ,   "交流瞬时过流"},
            {106 ,   "电网过频"},
            {107 ,   "电网欠频"},
            {108 ,   "孤岛"},
            {109 ,   "直流分量过流"},
            {110 ,   "漏电流过流"},
            {111 ,   "10分钟电网过压"},
            {112 ,   "电网高压"},
            {113 ,   "逆变过流硬件故障"},
            {114 ,   "电网高频"},
            {115 ,   "电网低频"} };
        private Dictionary<int, string> m_AlarmDesMapATS62 = new Dictionary<int, string>() {
            {201 ,   "环境过温"},
            {202 ,   "网侧继电器故障"},
            {203 ,   "漏电流采样通道故障"},
            {204 ,   "环境温度过低故障"},
            {205 ,   "逆变开环自检故障"},
            {206 ,   "PV1升压电路故障"},
            {207 ,   "PV2升压电路故障"},
            {208,    "" },
            {209 ,   "R相电流采样通道故障"},
            {210 ,   "INV开关管过温"},
            {211 ,   "PV绝缘阻抗故障"},
            {212 ,   "PV高压过功率保护"},
            {213 ,   "冗余故障"},
            {214 ,   "R相逆变电压采样通道故障"},
            {215 ,   "R相直流分量采样通道故障"},
            {216 ,   "PV1电流采样通道故障"},
            {217 ,   "PV2电流采样通道故障"},
            {218 ,   "PV1MPPT电流采样通道故障"},
            {219 ,   "PV2MPPT电流采样通道故障"},
            {220 ,   "漏电流CT自检故障"},
            {221 ,   "SPI通讯故障"},
            {222 ,   "LCD与主DSP通讯故障"},
            {223 ,   "交流接直流"},
            {224 ,   "Capture Circuit Fault"},
            {225 ,   "Redandant Initial Dsp Fault"} };
        private Dictionary<int, string> m_AlarmDesMapATS63 = new Dictionary<int, string>() {
            {501 ,   "EEPROM故障"},
            {502 ,   "RTC故障"},
            {503 ,   "与DSP通讯故障"} };
        private Dictionary<int, string> m_AlarmDesMapATS65 = new Dictionary<int, string>() {
            {301 ,   "pv过流永久性故障"},
            {302 ,   "INV过流永久性故障"},
            {303 ,   "直流分量高永久性故障"},
            {304 ,   "bus过压永久性故障"},
            {305 ,   "继电器永久性故障"},
            {306 ,   "Boost1开环自检故障"},
            {307 ,   "Boost2开环自检故障"},
            {308 ,   "逆变开环自检永久故障"},
            {309 ,   "环境高温传感器及逆变温度传感器一起故障"}
        };

        private Dictionary<int, Dictionary<int, string>> m_AlarmDesMapATSALL = new Dictionary<int, Dictionary<int, string>>();
        private void initATSAlarm()
        {
            m_AlarmDesMapATSALL.Add(0xff60, m_AlarmDesMapATS60);
            m_AlarmDesMapATSALL.Add(0xff61, m_AlarmDesMapATS61);
            m_AlarmDesMapATSALL.Add(0xff62, m_AlarmDesMapATS62);
            m_AlarmDesMapATSALL.Add(0xff63, m_AlarmDesMapATS63);
            m_AlarmDesMapATSALL.Add(0xff64, m_AlarmDesMapATS64);
            m_AlarmDesMapATSALL.Add(0xff65, m_AlarmDesMapATS65);
        }
        private Dictionary<int, string> m_AlarmDesMapHW50000 = new Dictionary<int, string>()
        {
            { 0x08,  "内部通讯故障" },
{0X0A    ,  "软件版本不匹配504" },
{0X0C    ,  "升级失败505" },
{0X0D    ,  "Flash故障61440" }
        };
        private Dictionary<int, string> m_AlarmDesMapHW50001 = new Dictionary<int, string>()
        {

{0X01,    "软件版本不匹配504" },
{0X02,    "软件版本不匹配504" },
{0X03,    "系统故障400" },
{0X04,    "系统故障400" },
{0X06,    "逆变电路异常202" },
{0X07,    "残余电流异常318" },
{0X08,    "温度过高321" },
{0X09,    "温度过高321" },
{0X0A,    "系统故障400" },
{0X0B,    "风扇故障320" },
{0X0C,    "SPI通讯异常322" },
{0X0E,    "系统故障400" },
{0X0F,    "系统故障" }
            };
        private Dictionary<int, string> m_AlarmDesMapHW50002 = new Dictionary<int, string>()
        {
{0X00,   "绝缘阻抗低313" },
{0X01,   "AFCI自检失败411" },
{0X02,   "直流电弧故障412" },
{0X03,   "AFCI自检失败411" },
{0X04,   "AFCI自检失败411" },
{0x05,   "残余电流异常" },
{0x06,   "温度过高" },
{0X07,   "浪涌保护器故障" },
{0X08,   "浪涌保护器故障" },
{0X09,   "组串3反向122" },
{0X0C,   "直流电弧故障412" },
{0X0D,   "直流电弧故障412" },
{0X0E,   "直流电弧故障412" },
{0X0F,   "系统故障400" } };
        private Dictionary<int, string> m_AlarmDesMapHW50003 = new Dictionary<int, string>()
        {
{0x00,   "系统故障 " },
{0X01,   "组串1反向120" },
{0X02,   "组串2反向121" },
{0X03,   "直流电路异常200" },
{0X06,   "组串4反向123" },
{0X07,   "组串5反向124" },
{0X08,   "组串6反向125" },
{0X09,   "DC输入电压高103" },
{0X0A,   "DC输入电压高103" },
{0X0B,  "DC输入电压高103" },
{0X0C,   "DC输入电压高103" },
{0X0F,   "直流电路异常200" } };
        private Dictionary<int, string> m_AlarmDesMapHW50004 = new Dictionary<int, string>()
        {
{0x01,   "温度过高" },
{0X02,   "组串1反向120" },
{0X03,   "组串2反向121" },
{0X04,   "组串7反向126" },
{0X05,   "组串7反向126" },
{0X06,   "组串8反向127" },
{0X07,   "组串8反向127" },
{0X0C,   "组串3反向122" },
{0X0D,   "组串4反向123" },
{0X0E,   "组串5反向124" },
{0X0F,   "组串6反向125" } };
        private Dictionary<int, string> m_AlarmDesMapHW50005 = new Dictionary<int, string>()
        {
{0x00,   "直流电路异常" },
{0X01,   "直流电路异常200" },
{0X02,   "辅助电源异常410" },
{0X04,   "直流电路异常200" },
{0X05,   "直流电路异常200" },
{0X06,   "直流电路异常200" },
{0x07,   "直流电路异常" },
{0x08,   "直流电路异常" },
{0x09,   "直流电路异常" },
{0x0b,   "电网电压异常" },
{0x0c,   "直流电路异常" } };
        private Dictionary<int, string> m_AlarmDesMapHW50006 = new Dictionary<int, string>()
        {
{0x00,   "逆变电路异常" },
{0X06,   "系统故障400" },
{0X0A,   "逆变电路异常202" },
{0X0C,   "逆变电路异常202" } };
        private Dictionary<int, string> m_AlarmDesMapHW50007 = new Dictionary<int, string>()
        {
{0X01,   "逆变电路异常202" },
{0X05,   "系统故障400" },
{0x06,   "逆变电路异常" },
{0x07,   "电网电压异常" },
{0x08,   "电网电压异常" },
{0x09,   "电网电压异常" } };
        private Dictionary<int, string> m_AlarmDesMapHW50008 = new Dictionary<int, string>()
        {
{0X00,   "电网电压异常301" },
{0X01,   "电网电压异常301" },
{0X02,   "电网电压异常301" },
{0X03,   "电网电压异常301" },
{0X04,   "电网电压异常301" },
{0X05,   "电网电压异常301" },
{0X06,   "电网频率异常305" },
{0X07,   "电网频率异常305" },
{0X08,   "电网电压异常301" },
{0X09,   "电网电压异常301" },
{0X0A,   "接地异常326" },
{0X0B,   "电网电压异常301" },
{0X0C,   "电网频率异常305" } };
        private Dictionary<int, string> m_AlarmDesMapHW50009 = new Dictionary<int, string>()
        {
{0X00,   "电网电压异常301" },
{0X01,   "电网电压异常301" },
{0X02,   "电网电压异常302" },
{0x05,   "系统故障 " },
{0x06,   "系统故障" },
{0x08,   "电网电压异常" } };
        private Dictionary<int, string> m_AlarmDesMapHW50011 = new Dictionary<int, string>()
        {
{0x08,   "逆变电路异常 " },
{0x0a,   "电网AB线电压高于允许范围" },
{0x0b,   "电网BC线电压高于允许范围 " },
{0x0c,   "电网CA线电压高于允许范围 " } };
        private Dictionary<int, string> m_AlarmDesMapHW50016 = new Dictionary<int, string>()
        {
{0X00,   "组串1异常106" },
{0X01,   "组串2异常107" },
{0X02,   "组串3异常108" },
{0X03,   "组串4异常109" },
{0X04,   "组串5异常110" },
{0X05,   "组串6异常111" },
{0X06,   "组串7异常112" },
{0X07,  "组串8异常113" } };


        private Dictionary<int, Dictionary<int, string>> m_AlarmDesHWAll = new Dictionary<int, Dictionary<int, string>>();

        public TcpServer TcpServer { get => m_TcpServer; set => m_TcpServer = value; }

        private void initHWAlarm()
        {
            m_AlarmDesHWAll.Add(0xff71, m_AlarmDesMapHW50000);
            m_AlarmDesHWAll.Add(0xff72, m_AlarmDesMapHW50001);
            m_AlarmDesHWAll.Add(0xff73, m_AlarmDesMapHW50002);
            m_AlarmDesHWAll.Add(0xff74, m_AlarmDesMapHW50003);
            m_AlarmDesHWAll.Add(0xff75, m_AlarmDesMapHW50004);
            m_AlarmDesHWAll.Add(0xff76, m_AlarmDesMapHW50005);
            m_AlarmDesHWAll.Add(0xff77, m_AlarmDesMapHW50006);
            m_AlarmDesHWAll.Add(0xff78, m_AlarmDesMapHW50007);
            m_AlarmDesHWAll.Add(0xff79, m_AlarmDesMapHW50008);
            m_AlarmDesHWAll.Add(0xff7a, m_AlarmDesMapHW50009);
            m_AlarmDesHWAll.Add(0xff7b, m_AlarmDesMapHW50011);
            m_AlarmDesHWAll.Add(0xff7c, m_AlarmDesMapHW50016);
        }



        public TcpSession GetSession(string EccAddr)
        {

            List<TcpSession> Sessions = GetSessions();
            lock ((Sessions as ICollection).SyncRoot)
            {
                for (int i = 0; i < Sessions.Count; i++)
                {
                    TcpSession Session = Sessions[i] as TcpSession;
                    if (Session.TagString == EccAddr)
                    {
                        return Session;
                    }
                }
            }
            return null;
        }
        public List<TcpSession> GetSessions()
        {
            return m_TcpServer.GetSessions();
        }
        public bool isOnline(string RtuSN)
        {
            TcpSession Session = GetSession(RtuSN);
            if (Session != null)
            {

                return true;
            }
            return false;
        }
        public bool Start(int Port, int backlog = 200)
        {

            bool b = m_TcpServer.Start(Port, backlog);
            task_SessionCheck.Start();// 先注释掉，不再检查掉线，观察，并且在后续版本中修改
            return b;

        }
        public void Stop()
        {
            if (m_TcpServer != null)
            {
                m_TcpServer.Stop();
                task_SessionCheck.Stop(); //先注释掉，不再检查掉线，观察，并且在后续版本中修改
                //m_TcpServer = null;
            }
        }

        public bool Send(string EccAddr, byte[] Data)
        {
            TcpSession Session = GetSession(EccAddr);
            if (Session != null)
            {
                try
                {
                    Send(Session, Data);
                    return true;
                }
                catch
                {
                    return false;
                }
            }
            return false;
        }
        public void Send(TcpSession Session, byte[] Data)
        {
            try
            {
                Session.Send(Data);
            }
            catch (Exception ee)
            {
                Log.Error("send error " + ee.Message + "|" + ee.StackTrace);
            }
            //Log.Info(Session.TagString, "send " + Util.BytesToHex(Data));
        }

        protected void OnReceiveDo(TcpSession Session)
        {
            while (true)
            {
                byte[] RFrame = null;
                try
                {
                    bool bContinue = ProtocolPV.GetFrame(Session.DataBuffer, out RFrame);
                    //未解析到帧
                    if (RFrame == null)
                    {
                        //可以继续获取帧
                        if (bContinue)
                        {
                            continue;
                        }
                        //需要接收数据
                        else
                        {
                            return;
                        }
                    }
                }
                catch (Exception ee)
                {
                    Log.Error("recv data error!" + ee.Message + "|" + ee.StackTrace);
                }
                Session.LastRecvProtocolFrameTime = DateTime.Now;
                //Log.Error(Util.BytesToHex(RFrame));
                string SN = "";
                if (Session.TagString != null)
                    SN = Session.TagString;
                Log.Info(SN, "RCV-session:[id-" + Session.SessionId + "][SN-" + SN + "]" + Util.BytesToHex(RFrame));
                //Log.Error(Util.BytesToHex(RFrame));
                //数据协议
                if (RFrame[0] == 0x69)
                {
                    //根据不同数据类型解析
                    int DataType = BitConverter.ToUInt16(RFrame, 14);
                    switch (DataType)
                    {
                        case 1:
                            try
                            {
                                OnReceiveDoLogin(Session, RFrame);
                            }
                            catch (Exception e1)
                            {
                                Log.Error("recv Login Frame ,Process Error " + e1.Message + "|" + e1.StackTrace);
                            }
                            break;
                        case 2:
                            try
                            {
                                OnRecvDoStaionInfo(Session, RFrame);
                            }
                            catch (Exception e2)
                            {
                                Log.Error("recv station Info ,Process Error " + e2.Message + "|" + e2.StackTrace);
                            }
                            break;
                        case 3:
                            try
                            {
                                OnRecvDoDeviceInfo(Session, RFrame);
                            }
                            catch (Exception e3)
                            {
                                Log.Error("recv device Info, Process Error  " + e3.Message + "|" + e3.StackTrace);
                            }
                            break;
                        case 4:
                            try
                            {
                                OnRecvDoRealData(Session, RFrame);
                            }
                            catch (Exception e4)
                            {
                                Log.Error("recv real Data ,Process Error  " + e4.Message + "|" + e4.StackTrace);
                            }
                            break;
                        case 5:
                            try
                            {
                                OnRecvDoHisData(Session, RFrame);
                            }
                            catch (Exception e5)
                            {
                                Log.Error("Recv HisData ,Process Error " + e5.Message + "|" + e5.StackTrace);
                            }
                            break;
                        case 6:
                            break;
                        case 8:
                            try
                            {
                                OnReceiveDoBeatHeart(Session, RFrame);
                            }
                            catch (Exception e8)
                            {
                                Log.Error("Recv BeatHeart " + e8.Message + "|" + e8.StackTrace);
                            }
                            break;
                        default:

                            break;
                    }
                }
                //维护协议
                else
                {
                    try
                    {
                        OnMaintainFrameReceive?.Invoke(RFrame);
                    }
                    catch (Exception em)
                    {
                        Log.Error("Recv MaintainFrame ,Process Error " + em.Message + "|" + em.StackTrace);
                    }
                }
            }
        }

        private void OnReceiveDoBeatHeart(TcpSession Session, byte[] RFrame)
        {
            try
            {
                List<byte> Data = new List<byte>();

                //密码不判断
                //if (Pwd == Session.TagObject.ToString())
                //{
                //    Data.Add(0x01);
                //    Data.Add(0x00);
                //}
                //else
                //{
                Data.Add(0x01);
                Data.Add(0x00);
                //}
                DateTime CurTime = DateTime.Now;
                Data.Add((byte)CurTime.Second);
                Data.Add((byte)CurTime.Minute);
                Data.Add((byte)CurTime.Hour);
                Data.Add((byte)CurTime.Day);
                Data.Add((byte)CurTime.Month);
                Data.Add((byte)(CurTime.Year - 2000));
                byte[] SFrame = ProtocolPV.BuildDataFrame(1, 4, Data.ToArray());
                Session.Send(SFrame);
            }
            catch (Exception ee)
            {
                Log.Error("beat heart process error " + ee.Message + "|" + ee.StackTrace);
            }
        }

        private void OnReceiveDoLogin(TcpSession Session, byte[] Frame)
        {
            int DataPos = 16;
            int DataFlag = BitConverter.ToUInt16(Frame, DataPos);
            DataPos += 2;
            if (DataFlag == 1)
            {
                string SN = Encoding.UTF8.GetString(Frame, DataPos, 16).Trim(new char[] { '\0' });
                DataPos += 16;
                List<TcpSession> Sessions = GetSessions();
                lock ((Sessions as ICollection).SyncRoot)
                {
                    //发送32字节随机字符串
                    string RandomStr = new Guid().ToString("N");
                    byte[] Data = Encoding.UTF8.GetBytes(RandomStr);
                    byte[] SFrame = ProtocolPV.BuildDataFrame(1, 2, Data);
                    Session.Send(SFrame);
                    //同一个SN老的连接未检测到断开的处理
                    for (int i = 0; i < Sessions.Count; i++)
                    {
                        TcpSession tmpSession = Sessions[i] as TcpSession;
                        //存在老的连接
                        if (Sessions[i].TagString == SN)
                        {
                            //关闭已存在session
                            Log.Info(SN + " has exist old session, will close old session");
                            Sessions[i].Close(m_TcpServer.GetSessionPool());
                            //m_TcpServer.GetSessionPool().Enqueue(Sessions[i]);
                            Sessions.RemoveAt(i);
                            break;
                        }
                    }
                    Session.TagString = SN;
                    string Pwd = Encoding.UTF8.GetString(Frame, DataPos, 32).Trim(new char[] { '\0' });
                    Session.TagObject = Pwd;
                    OnLogin?.Invoke(SN, Pwd);
                }
            }
            else if (DataFlag == 3)
            {
                string Pwd = Encoding.UTF8.GetString(Frame, DataPos, 32).Trim(new char[] { '\0' });
                //认证通过
                List<byte> Data = new List<byte>();

                //密码不判断
                //if (Pwd == Session.TagObject.ToString())
                //{
                //    Data.Add(0x01);
                //    Data.Add(0x00);
                //}
                //else
                //{
                Data.Add(0x01);
                Data.Add(0x00);
                //}
                DateTime CurTime = DateTime.Now;
                Data.Add((byte)CurTime.Second);
                Data.Add((byte)CurTime.Minute);
                Data.Add((byte)CurTime.Hour);
                Data.Add((byte)CurTime.Day);
                Data.Add((byte)CurTime.Month);
                Data.Add((byte)(CurTime.Year - 2000));
                byte[] SFrame = ProtocolPV.BuildDataFrame(1, 4, Data.ToArray());
                Session.Send(SFrame);

            }
            else
            {
                byte[] SFrame = ProtocolPV.BuildDataFrame(1, 0xffff, new byte[0]);
                Session.Send(SFrame);
            }
        }
        private void OnRecvDoStaionInfo(TcpSession Session, byte[] Frame)
        {
            byte[] SFrame = ProtocolPV.BuildDataFrame(2, 0xffff, new byte[4] { 0xFF, 0x00, 0x11, 0x00 });
            Session.Send(SFrame);
        }
        private void OnRecvDoDeviceInfo(TcpSession Session, byte[] Frame)
        {
            byte[] SFrame = ProtocolPV.BuildDataFrame(3, 0xffff, new byte[4] { 0xFF, 0x00, 0x31, 0x00 });
            Session.Send(SFrame);
        }

        public void OnRecvDoRealData(TcpSession Session, byte[] Frame)
        {
            if ((Session == null) || (Session.TagString == null) || (Session.TagString.Length == 0))
            {
                if (Session != null)
                {
                    m_TcpServer.CloseSession(Session);
                }

                return;
            }
            int version = BitConverter.ToInt16(Frame, 10);
            int deviceType = 9;
            int DataPos = 16;
            int DataFlag = BitConverter.ToUInt16(Frame, DataPos);
            DataPos += 2;
            //实时数据只有41标识
            if (DataFlag == 41)
            {
                int DevAddr = Frame[DataPos];
                //艾罗，低字节是逆变器地址
                //int DevAddr = BitConverter.ToInt16(Frame, DataPos);
                DataPos += 2;
                //状态码
                int StateCode = BitConverter.ToUInt16(Frame, DataPos);
                DataPos += 2;
                //时间戳
                DateTime ReportTime = new DateTime(Frame[DataPos + 5] + 2000,
                    Frame[DataPos + 4],
                    Frame[DataPos + 3],
                    Frame[DataPos + 2],
                    Frame[DataPos + 1],
                   0);
                DataPos += 6;
                //信息体个数
                int Count = BitConverter.ToUInt16(Frame, DataPos);
                DataPos += 2;

                Dictionary<int, dynamic> InvData = new Dictionary<int, dynamic>();
                Dictionary<int, dynamic> MeterData = new Dictionary<int, dynamic>();
                Dictionary<int, dynamic> SensorData = new Dictionary<int, dynamic>();
                List<dynamic> AlarmDatas = new List<dynamic>();
                /* if (StateCode == 2)
                 {
                     dynamic AlarmData = new ExpandoObject();
                     int errorcode = 101;
                     AlarmData.RtuSN = Session.TagString;
                     AlarmData.DevAddr = DevAddr;
                     AlarmData.DevType =1;
                     AlarmData.LogType = errorcode;
                     AlarmData.LogTime = ReportTime;
                     AlarmData.OriginCode = 101;
                     AlarmData.Note = "逆变器通讯异常";
                     AlarmData.Version = "1";
                     AlarmData.AckStatus = 0;
                     AlarmDatas.Add(AlarmData);
                 }*/
                // else
                //{
                for (int i = 0; i < Count; i++)
                {
                    int InfoType = Frame[DataPos];
                    DataPos++;
                    int MemAddr = BitConverter.ToUInt16(Frame, DataPos);
                    DataPos += 2;
                    if (InfoType == 1 || InfoType == 3)
                    {
                        //电站数据
                        if (MemAddr >= 1 && MemAddr <= 7)
                        {
                            ParseStationRealData(Frame, Session.TagString, Count, DataPos);
                        }
                        //逆变器数据
                        else if (MemAddr >= 201 && MemAddr <= 289)
                        {
                            AddDataItem(Session.TagString, InvData, Frame, MemAddr, DataPos, version.ToString());
                            if ((MemAddr == 224) && (version == 1))
                            {
                                int originerrorcode = BitConverter.ToInt32(Frame, DataPos);
                                dynamic errorInfo = CacheDevices.getErrorInfo(Session.TagString, DevAddr, (int)originerrorcode);
                                if (errorInfo != null)
                                {
                                    dynamic AlarmData = new ExpandoObject();
                                    int errorcode = errorInfo.JHCode;
                                    AlarmData.RtuSN = Session.TagString;
                                    AlarmData.DevAddr = DevAddr;
                                    AlarmData.DevType = errorcode / 100;
                                    AlarmData.LogType = errorcode;
                                    AlarmData.LogTime = ReportTime;
                                    AlarmData.Version = version.ToString();
                                    AlarmData.OriginCode = originerrorcode;
                                    if (m_AlarmDesMap[version.ToString()].ContainsKey((int)errorcode))
                                    {
                                        AlarmData.Note = m_AlarmDesMap[version.ToString()][(int)errorcode];
                                    }
                                    else
                                    {
                                        AlarmData.Note = "unknow";
                                    }

                                    AlarmData.AckStatus = 0;
                                    AlarmDatas.Add(AlarmData);
                                }
                            }
                        }
                        else if (MemAddr >= 410 && MemAddr <= 452)
                        {
                            AddDataItem(Session.TagString, SensorData, Frame, MemAddr, DataPos, version.ToString());
                        }
                        //电表数据
                        else if (MemAddr >= 501 && MemAddr <= 581)
                        {
                            AddDataItem(Session.TagString, MeterData, Frame, MemAddr, DataPos, version.ToString());

                        }
                        else if (MemAddr == 0xff00)
                        {
                            deviceType = BitConverter.ToInt32(Frame, DataPos);
                        }
                        else if ((MemAddr >= 0xff50) && (MemAddr <= 0xff52))
                        {//茂硕的故障
                            int errorCode = BitConverter.ToInt32(Frame, DataPos);
                            //0008 = 0000 0000 0000 1000 = 
                            //2000 = 0010 0000 0000 0000 
                            if ((((errorCode & 0x08) == 0x08) && (deviceType == 9)) || (((errorCode & 0x2000) == 0x2000) && (deviceType == 8)))
                            {
                                dynamic AlarmData = new ExpandoObject();
                                int errorcode = BitConverter.ToInt32(Frame, DataPos);
                                AlarmData.RtuSN = Session.TagString;
                                AlarmData.DevAddr = DevAddr;
                                AlarmData.DevType = errorcode / 100;
                                AlarmData.LogType = errorcode;
                                AlarmData.LogTime = ReportTime;
                                AlarmData.OriginCode = errorCode;
                                AlarmData.Note = "无电网";
                                AlarmData.Version = "1";
                                AlarmData.AckStatus = 0;
                                AlarmDatas.Add(AlarmData);
                            }
                        }
                        else if ((MemAddr >= 0xff60) && (MemAddr <= 0xff69))
                        {
                            int errorcode = BitConverter.ToInt32(Frame, DataPos);
                            Dictionary<int, string> alarmDic = new Dictionary<int, string>();
                            if (m_AlarmDesMapATSALL.TryGetValue(MemAddr, out alarmDic))
                            {
                                List<int> keys = alarmDic.Keys.ToList();
                                foreach (int key in keys)
                                {
                                    int seqno = key % 100;
                                    if (((errorcode >> (32 - seqno)) & 1) == 1)
                                    {
                                        dynamic AlarmData = new ExpandoObject();

                                        AlarmData.RtuSN = Session.TagString;
                                        AlarmData.DevAddr = DevAddr;
                                        AlarmData.DevType = key / 100;
                                        AlarmData.LogType = key;
                                        AlarmData.LogTime = ReportTime;
                                        AlarmData.OriginCode = key;
                                        AlarmData.Note = alarmDic[key];
                                        AlarmData.Version = "2";
                                        AlarmData.AckStatus = 0;
                                        AlarmDatas.Add(AlarmData);
                                    }
                                }
                            }
                        }
                        else if (MemAddr == 0xff70)
                        {
                            deviceType = BitConverter.ToInt32(Frame, DataPos);
                        }
                        else if ((MemAddr >= 0xff71) && (MemAddr <= 0xff7c))
                        {
                            int errorcode = BitConverter.ToInt32(Frame, DataPos);
                            Dictionary<int, string> alarmDic = new Dictionary<int, string>();
                            if (m_AlarmDesHWAll.TryGetValue(MemAddr, out alarmDic))
                            {
                                List<int> keys = alarmDic.Keys.ToList();
                                foreach (int key in keys)
                                {
                                    int seqno = key;
                                    int bit = (errorcode >> (seqno)) & 1;
                                    if (bit == 1)
                                    {
                                        dynamic AlarmData = new ExpandoObject();

                                        AlarmData.RtuSN = Session.TagString;
                                        AlarmData.DevAddr = DevAddr;
                                        AlarmData.DevType = 1;
                                        AlarmData.LogType = key;
                                        AlarmData.LogTime = ReportTime;
                                        AlarmData.OriginCode = key;
                                        AlarmData.Note = alarmDic[key];
                                        AlarmData.Version = "2";
                                        AlarmData.AckStatus = 0;
                                        AlarmDatas.Add(AlarmData);
                                    }
                                }
                            }
                        }
                        DataPos += 4;
                        DataPos += 1;//质量码
                    }
                    else if (InfoType == 2)
                    {
                        DataPos += 9;//暂时不解析
                    }
                    else
                    {
                        Log.Error("info type error,can not parse");
                        break;
                    }
                    // }
                }
                if (InvData.Count > 0)
                {
                    dynamic Data = new ExpandoObject();
                    Data.WriteTime = ReportTime;
                    Data.DataType = "Realdata";
                    Data.Version = version.ToString();
                    //Log.Error(Session.SessionId+"|"+Session.TagString+"|"+Session.TagObject+"|"+Session.TagInt);
                    Data.RtuSN = Session.TagString;
                    Data.Addr = DevAddr;
                    Data.Data = InvData;
                    OnInvDataReceive?.Invoke(Data);
                }
                if (MeterData.Count > 0)
                {
                    dynamic Data = new ExpandoObject();
                    Data.WriteTime = ReportTime;
                    Data.DataType = "Realdata";
                    Data.RtuSN = Session.TagString;
                    Data.Addr = DevAddr;
                    Data.Data = MeterData;
                    Data.Version = version.ToString();
                    OnMeterDataReceive?.Invoke(Data);
                }
                if (AlarmDatas.Count > 0)
                {

                    OnAlarmDataReceive?.Invoke(AlarmDatas);
                }
                if (SensorData.Count > 0)
                {
                    dynamic Data = new ExpandoObject();
                    Data.WriteTime = ReportTime;
                    Data.RtuSN = Session.TagString;
                    Data.Addr = DevAddr;
                    Data.Data = SensorData;
                    OnSensorDataReceive?.Invoke(Data);
                }
            }
        }
        private void OnRecvDoHisData(TcpSession Session, byte[] Frame)
        {
            int DataPos = 16;
            int version = BitConverter.ToInt16(Frame, 10);
            int DataFlag = BitConverter.ToUInt16(Frame, DataPos);
            DataPos += 2;
            int deviceType = 9;
            //故障信息
            if (DataFlag == 52)
            {
                int Count = BitConverter.ToUInt16(Frame, DataPos);
                DataPos += 2;
                List<dynamic> AlarmDatas = new List<dynamic>();
                for (int i = 0; i < Count; i++)
                {
                    int DevAddr = Frame[DataPos];
                    //艾罗，低字节是逆变器地址
                    //int DevAddr = BitConverter.ToUInt16(Frame, DataPos);
                    DataPos += 2;
                    int AlarmCode = BitConverter.ToUInt16(Frame, DataPos);
                    DataPos += 2;
                    string AlarmDes = Encoding.UTF8.GetString(Frame, DataPos, 32).Trim(new char[] { '\0' });
                    DataPos += 32;
                    DateTime ReportTime = new DateTime(2000 + Frame[DataPos + 6],
                                                       Frame[DataPos + 5],
                                                       Frame[DataPos + 4],
                                                       Frame[DataPos + 3],
                                                       Frame[DataPos + 2],
                                                      0);
                    DataPos += 7;
                    dynamic AlarmData = new ExpandoObject();
                    AlarmData.RtuSN = Session.TagString;
                    AlarmData.DevAddr = DevAddr;
                    AlarmData.DevType = AlarmCode / 100;
                    AlarmData.LogType = AlarmCode;
                    AlarmData.LogTime = ReportTime;
                    dynamic errorInfo = CacheDevices.getErrorInfo(Session.TagString, DevAddr, AlarmCode);
                    if (errorInfo != null)
                    {
                        int errorcode = errorInfo.JHCode;
                        AlarmData.OriginCode = errorcode;
                    }
                    else
                    {
                        AlarmData.OriginCode = AlarmCode;
                    }
                    if (m_AlarmDesMap[version.ToString()].ContainsKey(AlarmCode))
                    {
                        AlarmData.Note = m_AlarmDesMap[version.ToString()][AlarmCode];
                    }
                    else
                    {
                        AlarmData.Note = AlarmDes;
                    }

                    AlarmData.AckStatus = 0;
                    AlarmDatas.Add(AlarmData);

                }

                if (AlarmDatas.Count > 0)
                {

                    OnAlarmDataReceive?.Invoke(AlarmDatas);
                }

            }
            else if (DataFlag == 51)
            {//历史数据
                //Log.Error("recv hisdata-0 \r\n");
                int DevAddr = Frame[DataPos];
                //艾罗，低字节是逆变器地址
                //int DevAddr = BitConverter.ToInt16(Frame, DataPos);
                DataPos += 2;
                //状态码
                //int StateCode = BitConverter.ToUInt16(Frame, DataPos);
                //DataPos += 2;
                //时间戳
                DateTime ReportTime = new DateTime(Frame[DataPos + 5] + 2000,
                    Frame[DataPos + 4],
                    Frame[DataPos + 3],
                    Frame[DataPos + 2],
                    Frame[DataPos + 1],
                   0);
                DataPos += 6;
                //信息体个数
                int Count = BitConverter.ToUInt16(Frame, DataPos);
                DataPos += 2;
                //Log.Error("his data Count " + Count);
                Dictionary<int, dynamic> InvData = new Dictionary<int, dynamic>();
                Dictionary<int, dynamic> MeterData = new Dictionary<int, dynamic>();
                List<dynamic> AlarmDatas = new List<dynamic>();
                for (int i = 0; i < Count; i++)
                {
                    int InfoType = Frame[DataPos];
                    DataPos++;
                    int MemAddr = BitConverter.ToUInt16(Frame, DataPos);
                    DataPos += 2;
                    if (InfoType == 1 || InfoType == 3)
                    {
                        //电站数据
                        if (MemAddr >= 1 && MemAddr <= 7)
                        {
                            ParseStationRealData(Frame, Session.TagString, Count, DataPos);
                        }
                        //逆变器数据
                        else if (MemAddr >= 201 && MemAddr <= 289)
                        {
                            AddDataItem(Session.TagString, InvData, Frame, MemAddr, DataPos, version.ToString());
                            if ((MemAddr == 224) && (version == 1))
                            {
                                int originerrorcode = BitConverter.ToInt32(Frame, DataPos);
                                dynamic errorInfo = CacheDevices.getErrorInfo(Session.TagString, DevAddr, (int)originerrorcode);
                                if (errorInfo != null)
                                {
                                    dynamic AlarmData = new ExpandoObject();
                                    int errorcode = errorInfo.JHCode;
                                    AlarmData.RtuSN = Session.TagString;
                                    AlarmData.DevAddr = DevAddr;
                                    AlarmData.DevType = errorcode / 100;
                                    AlarmData.LogType = errorcode;
                                    AlarmData.LogTime = ReportTime;
                                    AlarmData.Version = version.ToString();
                                    AlarmData.OriginCode = originerrorcode;
                                    if (m_AlarmDesMap[version.ToString()].ContainsKey((int)errorcode))
                                    {
                                        AlarmData.Note = m_AlarmDesMap[version.ToString()][(int)errorcode];
                                    }
                                    else
                                    {
                                        AlarmData.Note = "unknow";
                                    }

                                    AlarmData.AckStatus = 0;
                                    AlarmDatas.Add(AlarmData);
                                }
                            }

                        }
                        //电表数据
                        else if (MemAddr >= 501 && MemAddr <= 581)
                        {
                            AddDataItem(Session.TagString, MeterData, Frame, MemAddr, DataPos, version.ToString());

                        }
                        else if (MemAddr == 0xff00)
                        {
                            deviceType = BitConverter.ToInt32(Frame, DataPos);
                        }
                        else if (MemAddr == 0xff50)
                        {//茂硕的故障
                            int errorCode = BitConverter.ToInt32(Frame, DataPos);
                            //0008 = 0000 0000 0000 1000 = 
                            //2000 = 0010 0000 0000 0000 
                            if ((((errorCode & 0x08) == 0x08) && (deviceType == 9)) || (((errorCode & 0x2000) == 0x2000) && (deviceType == 8)))
                            {
                                dynamic AlarmData = new ExpandoObject();
                                int errorcode = 145;
                                AlarmData.RtuSN = Session.TagString;
                                AlarmData.DevAddr = DevAddr;
                                AlarmData.DevType = errorcode / 100;
                                AlarmData.LogType = errorcode;
                                AlarmData.LogTime = ReportTime;
                                AlarmData.OriginCode = errorCode;
                                AlarmData.Note = "无电网";
                                AlarmData.Version = "1";
                                AlarmData.AckStatus = 0;
                                AlarmDatas.Add(AlarmData);
                            }
                        }
                        DataPos += 4;
                        DataPos += 1;//质量码
                    }
                    else if (InfoType == 2)
                    {
                        DataPos += 9;//暂时不解析
                    }
                    else
                    {
                        Log.Error("info type error,can not parse");
                        break;
                    }
                }
                if (InvData.Count > 0)
                {
                    dynamic Data = new ExpandoObject();
                    Data.WriteTime = ReportTime;
                    Data.DataType = "Hisdata";
                    //Log.Error(Session.SessionId+"|"+Session.TagString+"|"+Session.TagObject+"|"+Session.TagInt);
                    Data.RtuSN = Session.TagString;
                    Data.Addr = DevAddr;
                    Data.Data = InvData;
                    Data.Version = version.ToString();
                    //Log.Error("recv Hisdata ");
                    OnInvDataReceive?.Invoke(Data);
                }
                if (MeterData.Count > 0)
                {
                    dynamic Data = new ExpandoObject();
                    Data.WriteTime = ReportTime;
                    Data.DataType = "Hisdata";
                    Data.RtuSN = Session.TagString;
                    Data.Addr = DevAddr;
                    Data.Data = MeterData;
                    Data.Version = version.ToString();
                    OnMeterDataReceive?.Invoke(Data);
                }
                if (AlarmDatas.Count > 0)
                {

                    OnAlarmDataReceive?.Invoke(AlarmDatas);
                }

            }
        }

        private void ParseStationRealData(byte[] Frame, string SN, int Count, int DataPos)
        {
            dynamic Data = new ExpandoObject();
            Data.SN = SN;
            Data.WriteTime = DateTime.Now;

            for (int i = 0; i < Count; i++)
            {
                DataPos++;
                int MemAddr = BitConverter.ToUInt16(Frame, DataPos);
                DataPos += 2;
                switch (MemAddr)
                {
                    case 1:
                        Data.E_Day = BitConverter.ToUInt32(Frame, DataPos) / 10;
                        break;
                    case 2:
                        Data.E_Total = BitConverter.ToUInt32(Frame, DataPos) / 10;
                        break;
                    case 3:
                        Data.D_H = BitConverter.ToUInt32(Frame, DataPos);
                        break;
                    case 4:
                        Data.D_V = BitConverter.ToUInt32(Frame, DataPos);
                        break;
                    case 5:
                        Data.T_Env = BitConverter.ToInt32(Frame, DataPos) / 10;
                        break;
                    case 6:
                        Data.T_Battery = BitConverter.ToInt32(Frame, DataPos) / 10;
                        break;
                    case 7:
                        Data.P = BitConverter.ToInt32(Frame, DataPos) / 10;
                        break;
                }
                DataPos += 4;
            }
        }

        private void AddDataItem(string SN, Dictionary<int, dynamic> Data, byte[] Frame, int MemAddr, int DataPos)
        {
            AddDataItem(SN, Data, Frame, MemAddr, DataPos, "1");
        }

        private void AddDataItem(string SN, Dictionary<int, dynamic> Data, byte[] Frame, int MemAddr, int DataPos, string version)
        {

            if (Data.ContainsKey(MemAddr))
            {
                Log.Error("SN:" + SN + ",data addr " + MemAddr + " exist");
                return;
            }
            if (!ProtocolPV.DataItems[version].ContainsKey(MemAddr))
            {
                Log.Error("SN:" + SN + ",data addr " + MemAddr + " not define");
                return;
            }
            ProtocolDataItem Item = ProtocolPV.DataItems[version][MemAddr];
            switch (Item.DataType)
            {
                case "uint32":
                    Data.Add(MemAddr, BitConverter.ToUInt32(Frame, DataPos) * Item.Mul);
                    break;
                case "int32":
                    Data.Add(MemAddr, BitConverter.ToInt32(Frame, DataPos) * Item.Mul);
                    break;
                case "int16":
                    Int16 v = BitConverter.ToInt16(Frame, DataPos);

                    Data.Add(MemAddr, v * Item.Mul);
                    break;
            }
        }

        private JsonValue ParseMaintainFrame(byte[] Frame)
        {
            JsonValue Cmd = new JsonObject();
            switch (Frame[5])
            {
                case 0xF0:
                    break;
                case 0xF1:
                    break;
            }

            return Cmd;
        }
    }
}
